package com.file.parser;

import com.file.bo.ResponseData;
import com.file.bo.mail.BOC;
import com.file.bo.mail.BOCTran;
import com.file.constant.ErrorCode;
import com.file.util.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.pdfbox.pdmodel.PDDocument;
import technology.tabula.*;
import technology.tabula.detectors.NurminenDetectionAlgorithm;
import technology.tabula.extractors.SpreadsheetExtractionAlgorithm;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static org.apache.poi.ss.usermodel.Sheet.TopMargin;

@Slf4j
public class BOCPdfParser extends BaseDecryptPdfParser {

    public ResponseData<String> parseBocPdfToJson(String daId, String filePath, String pdfPwd) {
        log.info("parseBocPdfToJson started, daId:{}", daId);
        String json = null;

        try {
            BOC boc = parseBocPdf(filePath, pdfPwd);
            json = JsonUtils.convertObjectToJson(boc);
        } catch (Exception e) {
            log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_EXCEPTION.getCode(), daId, "", "", "parseBocPdfToJson failed", e);
            return new ResponseData<String>(json, ErrorCode.FILE_PARSE_EXCEPTION.getCode(), ErrorCode.FILE_PARSE_EXCEPTION.getMsg());
        }

        log.info("parseBocPdfToJson completed, daId:{}", daId);
        return new ResponseData<String>(json, ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg());
    }

    public BOC parseBocPdf(String filePath, String pdfPwd) {

        BOC boc = parseBocHeader(filePath, pdfPwd);
        List<BOCTran> bocTrans = parseTrans(filePath, pdfPwd);
        boc.setBocTrans(bocTrans);

        return boc;
    }

    public BOC parseBocHeader(String filePath, String pdfPwd) {
        BOC boc = new BOC();
        String pdfHeaderText = parsePdfHeaderText(filePath, pdfPwd);
        String tradeRange = pdfHeaderText.substring(pdfHeaderText.indexOf("交易区间：") + 5, pdfHeaderText.indexOf("客户姓名")).trim();
        String customerName = pdfHeaderText.substring(pdfHeaderText.indexOf("客户姓名：") + 5, pdfHeaderText.indexOf("打印时间")).trim();
        String printTime = pdfHeaderText.substring(pdfHeaderText.indexOf("打印时间：") + 5, pdfHeaderText.indexOf("页数")).trim();
        String debitCardNo = pdfHeaderText.substring(pdfHeaderText.indexOf("借记卡号：") + 5, pdfHeaderText.indexOf("借方发生数")).trim();
        String accountNumber = pdfHeaderText.substring(pdfHeaderText.indexOf("账号：") + 3, pdfHeaderText.indexOf("按收支筛选")).trim();
        String filterByRevenueAndExpense = pdfHeaderText.substring(pdfHeaderText.indexOf("按收支筛选：") + 6, pdfHeaderText.indexOf("按币种筛选")).trim();
        String filterByCurrency = pdfHeaderText.substring(pdfHeaderText.indexOf("按币种筛选：") + 6, pdfHeaderText.indexOf("记账日期")).trim();
        boc.setTradeRange(tradeRange);
        boc.setCustomerName(customerName);
        boc.setPrintTime(printTime);
        boc.setDebitCardNo(debitCardNo);
        boc.setAccountNumber(accountNumber);
        boc.setFilterByRevenueAndExpense(filterByRevenueAndExpense);
        boc.setFilterByCurrency(filterByCurrency);
        return boc;
    }

    public List<BOCTran> parseTrans(String filePath, String pdfPwd) {
        List<BOCTran> bocTrans = new ArrayList<>();

        // 1. 读取文件
        File pdf = new File(filePath);

        // 2. pdfbox读取PDDocument
        try (PDDocument pdfDocument = PDDocument.load(pdf, pdfPwd)) {

            // 3. tabula新建ObjectExtractor和NurminenDetectionAlgorithm，同时准备接收表格Rectangle的结构
            ObjectExtractor objectExtractor = new ObjectExtractor(pdfDocument);
            NurminenDetectionAlgorithm detectionAlgorithm = new NurminenDetectionAlgorithm();
            Map<Integer, List<Rectangle>> detectedTables = new HashMap<>();

            // 4. 获取每页的PageIterator
            PageIterator pages = objectExtractor.extract();

            // 5. 解析每页的Rectangle(table的位置)
            while (pages.hasNext()) {
                Page page = pages.next();
                List<Rectangle> tablesOnPage = detectionAlgorithm.detect(page);
                if (tablesOnPage.size() > 0) {
                    detectedTables.put(Integer.valueOf(page.getPageNumber()), tablesOnPage);
                }
            }

            // 6.通过table位置获取表格具体内容
            SpreadsheetExtractionAlgorithm sea = new SpreadsheetExtractionAlgorithm();

            // 如果单页pdf中有多个表格，则解析出来的List<Rectangle>会有多个对象
            for (Map.Entry<Integer, List<Rectangle>> entry : detectedTables.entrySet()) {
                Page page = objectExtractor.extract(entry.getKey());

                // 丰巢中行默认每页只有一个表格，因此获取第0个rectangle
                Rectangle rectangle = entry.getValue().get(0);
                rectangle.setBottom(rectangle.getBottom() + TopMargin);
                Page area = page.getArea(rectangle);

                List<Table> table = sea.extract(area);

                // 丰巢中行默认每页只有一个表格，因此获取第0个table
                Table t = table.get(0);
                for (int i = 0; i < t.getRowCount(); i++) {
                    if (t.getCell(i, 0).getText(false).contains("记账日期")) {
                        continue;
                    }
                    BOCTran bocTran = getTransactionByTable(t, i);
                    bocTrans.add(bocTran);
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return bocTrans;
    }

    private BOCTran getTransactionByTable(Table t, int i) {
        BOCTran bocTran = new BOCTran();
        bocTran.setBookkeepingDate(t.getCell(i, 0).getText(false));
        bocTran.setBookkeepingTime(t.getCell(i, 1).getText(false));
        bocTran.setCurrency(t.getCell(i, 2).getText(false));
        bocTran.setAmount(t.getCell(i, 3).getText(false));
        bocTran.setBalance(t.getCell(i, 4).getText(false));
        bocTran.setTransactionName(t.getCell(i, 5).getText(false));
        bocTran.setChannel(t.getCell(i, 6).getText(false));
        bocTran.setOutletName(t.getCell(i, 7).getText(false));
        bocTran.setPostscript(t.getCell(i, 8).getText(false));
        if (t.getColCount() > 9) {
            bocTran.setOppositeAccountName(t.getCell(i, 9).getText(false));
            bocTran.setOppositeCardNo(t.getCell(i, 10).getText(false));
            bocTran.setOppositeBankOfDeposit(t.getCell(i, 11).getText(false));
        }
        return bocTran;
    }

    public static void main(String[] args) throws Exception {
        BOCPdfParser bocPdfParser = new BOCPdfParser();
        BOC boc = bocPdfParser.parseBocPdf("D:\\data\\files\\BOC\\中国银行流水（334423）.pdf", "334423");
//        BOC boc = bocPdfParser.parseBocPdf("D:\\data\\files\\BOC\\CgBRamV1fKWAHqqCABCgKZfC3HI359-405000.pdf", "405000");
        String jsonFilePath = "D:\\data\\files\\BOC\\中国银行流水（334423）.json";
        String json = JsonUtils.convertObjectToJson(boc);
        System.out.println(json);

//        File jsonFile = new File(jsonFilePath);
//        FileUtils.write(jsonFile, json, "UTF-8");
//        jsonFile.createNewFile();
    }

}
